{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "# -*- coding:utf-8 -*-\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "# from sklearn.model_selection import train_test_split\n",
    "# from sklearn.linear_model import LogisticRegressionCV\n",
    "from sklearn import metrics\n",
    "# from sklearn.preprocessing import label_binarize\n",
    "# from sklearn import preprocessing\n",
    "# from sklearn import tree \n",
    "\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.init as init\n",
    "import torchvision.transforms as transforms\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "import scipy.io as scio\n",
    "# import hiddenlayer as h\n",
    "from visdom import Visdom\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "from torchvision import transforms\n",
    "from torchsummary import summary\n",
    "from torchviz import make_dot\n",
    "\n",
    "import datetime\n",
    "import os \n",
    "\n",
    "import sys\n",
    "from utils.reuse import *\n",
    "from utils.networks import *\n",
    "# for auto-reloading external modules\n",
    "# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython\n",
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "device=torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "print(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2022_03_19_19_21_58\n"
     ]
    }
   ],
   "source": [
    "# 以下是检查点路径\n",
    "# 请在当前环境下 CMD 输入python -m visdom.server 或 visdom 启动监视器\n",
    "# 数据处理现在已移至 emgDataprocess.ipynb\n",
    "model_Dir = './/model//emgmk_cnn_0313//'\n",
    "if not os.path.exists(model_Dir):\n",
    "    os.makedirs(model_Dir)\n",
    "\n",
    "ckpDir = './/ckp//emgmk_cnn_0313//oth//'\n",
    "if not os.path.exists(ckpDir):\n",
    "    os.makedirs(ckpDir)\n",
    "\n",
    "ckpDir_auc = './/ckp//emgmk_cnn_0313//auc//'\n",
    "if not os.path.exists(ckpDir_auc):\n",
    "    os.makedirs(ckpDir_auc)\n",
    "\n",
    "def get_current_time():\n",
    "    return datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')\n",
    "print(get_current_time())\n",
    "\n",
    "timeForSave = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Setting up a new session...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "visdom has started\n"
     ]
    }
   ],
   "source": [
    "# 以下是 visdom 监视窗口初始化，实现每次启用时重新加载，这里只写了 NameError 以防其他错误不能被发现\n",
    "class visdom_account:\n",
    "    def __init__(self):    \n",
    "        self.port = 8097\n",
    "        self.server = \"http://localhost\"\n",
    "        self.base_url = \"/\"\n",
    "        self.username = \"admin\"\n",
    "        self.passward = \"1234\"\n",
    "        self.evns = \"train\"\n",
    "viz_acnt = visdom_account()\n",
    "vislogDir = model_Dir+'vislog//'\n",
    "if not os.path.exists(vislogDir):\n",
    "    os.makedirs(vislogDir)\n",
    "def viz_init():\n",
    "    try:\n",
    "        viz\n",
    "    except NameError:\n",
    "        viz = Visdom(env=viz_acnt.evns,log_to_filename=vislogDir+'vislog_'+timeForSave)\n",
    "        print('visdom has started')\n",
    "    else:\n",
    "        viz.close()\n",
    "        del viz\n",
    "        print('last visdom session closed')\n",
    "        viz = Visdom(env=viz_acnt.evns,log_to_filename=vislogDir+'vislog_'+timeForSave)\n",
    "        print('visdom has restarted')\n",
    "    return viz\n",
    "viz = viz_init()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------------------------------\n",
      "        Layer (type)               Output Shape         Param #\n",
      "================================================================\n",
      "            Linear-1               [1, 1, 1, 1]               3\n",
      "================================================================\n",
      "Total params: 3\n",
      "Trainable params: 3\n",
      "Non-trainable params: 0\n",
      "----------------------------------------------------------------\n",
      "Input size (MB): 0.00\n",
      "Forward/backward pass size (MB): 0.00\n",
      "Params size (MB): 0.00\n",
      "Estimated Total Size (MB): 0.00\n",
      "----------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# 自定义神经网络,CNN\n",
    "def get_num_correct(preds, labels):\n",
    "    return preds.argmax(dim=1).eq(labels).sum().item()\n",
    "# hdreshape = 1*32*5*12\n",
    "hdreshape = 2\n",
    "hdlayer_1 = 16\n",
    "hdlayer_2 = 2\n",
    "hdlayer_3 = 256\n",
    "class Network(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32,\\\n",
    "             kernel_size=3, padding=1)\n",
    "        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32,\\\n",
    "             kernel_size=3, padding=1)\n",
    "        self.conv3 = nn.Conv2d(in_channels=32, out_channels=32, \\\n",
    "            kernel_size=3, padding=0)\n",
    "\n",
    "        self.fc1 = nn.Linear(in_features=hdreshape, out_features=hdlayer_1)\n",
    "        self.fc2 = nn.Linear(in_features=hdlayer_1, out_features=hdlayer_2)\n",
    "        # self.fc3 = nn.Linear(in_features=hdlayer_2, out_features=hdlayer_3)\n",
    "        self.out = nn.Linear(in_features=hdlayer_2, out_features=1)\n",
    "        self.dr1 = nn.Dropout2d(0.2)\n",
    "\n",
    "    def forward(self, t):\n",
    "        # (1) input layer\n",
    "        t = t\n",
    "        # t = t.reshape(5,12)\n",
    "        # t = t.unsqueeze(0)\n",
    "\n",
    "        # (2) hidden conv layer\n",
    "        # t = self.conv1(t)\n",
    "        # t = F.relu(t)\n",
    "        # t = F.max_pool2d(t, kernel_size=2, stride=1)\n",
    "\n",
    "        # (3) hidden conv layer\n",
    "        # t = self.conv2(t)\n",
    "        # t = F.relu(t)\n",
    "        # t = self.dr1(t)\n",
    "        # t = F.max_pool2d(t, kernel_size=2, stride=1)\n",
    "\n",
    "        # (4) hidden linear layer\n",
    "        # t = t.reshape(-1, hdreshape)\n",
    "        # t = t.flatten(start_dim=0)\n",
    "        # t = self.fc1(t)\n",
    "        # t = F.relu(t)\n",
    "        # t = self.fc2(t)\n",
    "        # t = F.relu(t)\n",
    "        # t = self.fc3(t)\n",
    "        # t = F.relu(t)\n",
    "        # t = self.dr1(t)\n",
    "\n",
    "        # (5) output layer\n",
    "        t = self.out(t)\n",
    "\n",
    "        return t\n",
    "\n",
    "net = Network()\n",
    "# 打印网络，检查输入输出 shape是否正确\n",
    "# print(net)\n",
    "summary(net,(1,1,2),batch_size = 1,device = \"cpu\")\n",
    "# 可视化结构，torchviz\n",
    "sampleInput = torch.randn(1,1,1,2).requires_grad_(True)\n",
    "sampleOutput = net(sampleInput)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'dict'>\n",
      "(81, 1) (20, 1)\n",
      "(76, 10) (15, 1)\n",
      "torch.Size([20, 2]) torch.Size([81, 2]) torch.Size([81, 3])\n"
     ]
    }
   ],
   "source": [
    "\n",
    "dataarray = np.load('../data/220319emgsk/EMGSKdata_220321_free.npy',allow_pickle=True)\n",
    "CNNdataset = dataarray.item()\n",
    "print(type(CNNdataset))\n",
    "# 加载自变量：\n",
    "data_cyc = CNNdataset['data_cyc']\n",
    "data_emg_rf_l = CNNdataset['data_emg_rf_l']\n",
    "data_emg_lh_l = CNNdataset['data_emg_lh_l']\n",
    "data_mf_rf_l = CNNdataset['data_mf_rf_l']\n",
    "data_mf_bm_l = CNNdataset['data_mf_bm_l']\n",
    "data_ka_l = CNNdataset['data_ka_l']\n",
    "\n",
    "# 划分训练集与测试集\n",
    "def DataSpliter(data):\n",
    "    data_tr = []\n",
    "    data_te = []\n",
    "    for i in range(len(data)):\n",
    "        if (i+1)%5 == 0:\n",
    "            data_te.append(data[i,:])\n",
    "        else:\n",
    "            data_tr.append(data[i,:])\n",
    "    data_tr = np.array(data_tr)\n",
    "    data_te = np.array(data_te)\n",
    "    return data_tr, data_te\n",
    "tr_cyc,te_cyc = DataSpliter(data_cyc)\n",
    "print(tr_cyc.shape,te_cyc.shape)\n",
    "tr_mf_bm_l,te_mf_bm_l = DataSpliter(data_mf_bm_l)\n",
    "tr_emg_rf_l,te_emg_rf_l = DataSpliter(data_emg_rf_l)\n",
    "tr_emg_lh_l,te_emg_lh_l = DataSpliter(data_emg_lh_l)\n",
    "tr_mf_rf_l,te_mf_rf_l = DataSpliter(data_mf_rf_l)\n",
    "tr_ka_l,te_ka_l = DataSpliter(data_ka_l)\n",
    "\n",
    "# 按需组合数据，这两函数其实可以合并成一个\n",
    "def Data_conbine(data_1,data_2):\n",
    "    data_train = []\n",
    "    for i in range(len(data_1)):\n",
    "        data_1_2 = np.hstack((data_1[i,:],data_2[i,:]))\n",
    "        data_1_2 = data_1_2.flatten()\n",
    "        data_train.append(data_1_2)\n",
    "    data_train = np.array(data_train)\n",
    "    return data_train\n",
    "\n",
    "def establish_multi_timestep_data(data_X,data_X_2,data_Y,expect_time_length):\n",
    "    dataset = []\n",
    "    dataset_y = []\n",
    "    if expect_time_length >0:\n",
    "        length = len(data_X)-expect_time_length\n",
    "        for i in range(length):\n",
    "            data_1 = data_X[i:i+expect_time_length,:]\n",
    "            data_1 = data_1.flatten()\n",
    "            data_2 = data_X_2[i:i+expect_time_length,:]\n",
    "            data_2 = data_2.flatten()\n",
    "            data_12 = np.hstack((data_1,data_2))\n",
    "            dataset.append(data_12)\n",
    "            dataset_y.append(data_Y[i+expect_time_length-1,:])\n",
    "        dataset = np.array(dataset)\n",
    "        dataset_y = np.array(dataset_y)\n",
    "    return dataset, dataset_y\n",
    "\n",
    "data_12_tr = Data_conbine(tr_cyc,tr_emg_rf_l)\n",
    "data_12_te = Data_conbine(te_cyc,te_emg_rf_l)\n",
    "data_13_tr = Data_conbine(tr_cyc,tr_emg_lh_l)\n",
    "data_13_te = Data_conbine(te_cyc,te_emg_lh_l)\n",
    "data_123_tr = Data_conbine(data_12_tr,tr_emg_lh_l)\n",
    "data_123_te = Data_conbine(data_12_te,te_emg_lh_l)\n",
    "\n",
    "data_13_tr_5t,data_13_tr_5t_y = establish_multi_timestep_data(tr_cyc,tr_emg_lh_l,tr_mf_bm_l,5)\n",
    "data_13_te_5t,data_13_te_5t_y = establish_multi_timestep_data(te_cyc,te_emg_lh_l,te_mf_bm_l,5)\n",
    "print(data_13_tr_5t.shape,data_13_te_5t_y.shape)\n",
    "# 转为 tensor 格式\n",
    "data_12_tr = torch.from_numpy(data_12_tr)\n",
    "data_12_te = torch.from_numpy(data_12_te)\n",
    "data_13_tr = torch.from_numpy(data_13_tr)\n",
    "data_13_te = torch.from_numpy(data_13_te)\n",
    "data_123_tr = torch.from_numpy(data_123_tr)\n",
    "data_123_te = torch.from_numpy(data_123_te)\n",
    "tr_mf_rf_l = torch.from_numpy(tr_mf_rf_l)\n",
    "te_mf_rf_l = torch.from_numpy(te_mf_rf_l)\n",
    "tr_mf_bm_l = torch.from_numpy(tr_mf_bm_l)\n",
    "te_mf_bm_l = torch.from_numpy(te_mf_bm_l)\n",
    "tr_ka_l = torch.from_numpy(tr_ka_l)\n",
    "te_ka_l = torch.from_numpy(te_ka_l)\n",
    "\n",
    "data_12_tr = data_12_tr.to(torch.float32)\n",
    "data_12_te = data_12_te.to(torch.float32)\n",
    "data_13_tr = data_13_tr.to(torch.float32)\n",
    "data_13_te = data_13_te.to(torch.float32)\n",
    "data_123_tr = data_123_tr.to(torch.float32)\n",
    "data_123_te = data_123_te.to(torch.float32)\n",
    "tr_mf_rf_l = tr_mf_rf_l.to(torch.float32)\n",
    "te_mf_rf_l = te_mf_rf_l.to(torch.float32)\n",
    "tr_mf_bm_l = tr_mf_bm_l.to(torch.float32)\n",
    "te_mf_bm_l = te_mf_bm_l.to(torch.float32)\n",
    "tr_ka_l = tr_ka_l.to(torch.float32)\n",
    "te_ka_l = te_ka_l.to(torch.float32)\n",
    "\n",
    "data_13_tr_5t = torch.from_numpy(data_13_tr_5t).to(torch.float32)\n",
    "data_13_te_5t = torch.from_numpy(data_13_te_5t).to(torch.float32)\n",
    "data_13_tr_5t_y = torch.from_numpy(data_13_tr_5t_y).to(torch.float32)\n",
    "data_13_te_5t_y = torch.from_numpy(data_13_te_5t_y).to(torch.float32)\n",
    "print(data_12_te.shape,data_13_tr.shape,data_123_tr.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 1000 MSE_tr: 12189.5537109375\n",
      "epoch 2000 MSE_tr: 12190.6328125\n",
      "epoch 3000 MSE_tr: 12189.58984375\n",
      "epoch 4000 MSE_tr: 12189.6416015625\n",
      "epoch 5000 MSE_tr: 12191.4306640625\n",
      "epoch 6000 MSE_tr: 12189.630859375\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_24256/1170089131.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     39\u001b[0m     \u001b[1;31m# trainloss = criterion(preds.to(device), data_train_MF.to(device))\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     40\u001b[0m     \u001b[0moptimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mzero_grad\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 41\u001b[1;33m     \u001b[0mtrainloss\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# Calculate Gradients\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     42\u001b[0m     \u001b[0moptimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# Update Weight\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     43\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\ml2\\lib\\site-packages\\torch\\_tensor.py\u001b[0m in \u001b[0;36mbackward\u001b[1;34m(self, gradient, retain_graph, create_graph, inputs)\u001b[0m\n\u001b[0;32m    253\u001b[0m                 \u001b[0mcreate_graph\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mcreate_graph\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    254\u001b[0m                 inputs=inputs)\n\u001b[1;32m--> 255\u001b[1;33m         \u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mautograd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgradient\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mretain_graph\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcreate_graph\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0minputs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0minputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    256\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    257\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mregister_hook\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mhook\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\ml2\\lib\\site-packages\\torch\\autograd\\__init__.py\u001b[0m in \u001b[0;36mbackward\u001b[1;34m(tensors, grad_tensors, retain_graph, create_graph, grad_variables, inputs)\u001b[0m\n\u001b[0;32m    145\u001b[0m         \u001b[0mretain_graph\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcreate_graph\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    146\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 147\u001b[1;33m     Variable._execution_engine.run_backward(\n\u001b[0m\u001b[0;32m    148\u001b[0m         \u001b[0mtensors\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgrad_tensors_\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mretain_graph\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcreate_graph\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0minputs\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    149\u001b[0m         allow_unreachable=True, accumulate_grad=True)  # allow_unreachable flag\n",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "# CNN 训练\n",
    "net = Network()\n",
    "# 损失\n",
    "# criterion = nn.BCEWithLogitsLoss().to(device)\n",
    "criterion = torch.nn.MSELoss()\n",
    "# criterion = nn.SmoothL1Loss()\n",
    "# loss = torch.sqrt(criterion(x, y))\n",
    "# 加载数据，设置优化器\n",
    "# train_loader = torch.utils.data.DataLoader(train_set, batch_size=4,shuffle=True)\n",
    "# val_loader = torch.utils.data.DataLoader(train_set, batch_size=1,shuffle=True)\n",
    "# test_loader = torch.utils.data.DataLoader(test_set, batch_size=1,shuffle=True)\n",
    "# optimizer = torch.optim.Adam(net.parameters(),\n",
    "#         lr=0.00002)\n",
    "optimizer = torch.optim.Adam(net.parameters())\n",
    "# lr_schedule = torch.optim.lr_scheduler.StepLR(\\\n",
    "#         optimizer, 1, gamma=0.8, last_epoch=-1)\n",
    "# 初始化 visdom \n",
    "# viz.close()\n",
    "# viz = viz_init()\n",
    "vislogDir = './/vislog_ndata//cnn//'\n",
    "if not os.path.exists(vislogDir):\n",
    "    os.makedirs(vislogDir)\n",
    "# viz = Visdom(env=viz_acnt.evns, log_to_filename=vislogDir+'vislog_'+get_current_time())\n",
    "# vizx = 0\n",
    "# viz.text('MONITOR: Show train process~~',win='Monitor', opts = {'title':'ProcessMonitor',},)\n",
    "\n",
    "# total_test_acc = 0\n",
    "# total_test_correct = 0\n",
    "# totaltest = 0\n",
    "# 训练过程\n",
    "epoch_num = 4000000\n",
    "net.to(device)\n",
    "for epoch in range(epoch_num):\n",
    "\n",
    "    # net.train()\n",
    "    preds = net(data_13_tr.to(device)) \n",
    "    # trainloss = torch.sqrt(criterion(preds.to(device), data_train_MF.to(device)))\n",
    "    trainloss = criterion(preds.to(device), tr_mf_bm_l.to(device))\n",
    "    # trainloss = criterion(preds.to(device), data_train_MF.to(device))\n",
    "    optimizer.zero_grad()\n",
    "    trainloss.backward() # Calculate Gradients\n",
    "    optimizer.step() # Update Weight\n",
    "\n",
    "    if (epoch+1) % 1000 ==0:\n",
    "        print(\n",
    "            \"epoch\", epoch+1, \n",
    "            \"MSE_tr:\", float(trainloss),\n",
    "        )\n",
    "\n",
    "    \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "# checkpointPath_model = model_Dir+'c_final_'+'acc'+str(int(total_test_acc*10000))+'_'+timeForSave+'.pth'\n",
    "checkpointPath_model = model_Dir+'kmmf_final_'+'_'+timeForSave+'.pth'\n",
    "torch.save(net.state_dict(),checkpointPath_model)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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8Oab7v211IARcRcuXMrL4cYb4Y03SLn199wzYRpd2jW339bfHx55BGbMgHnzzCi+1InMh+cjJQWCgupVUezz0SqqEV3jwpm/I73mxlVRCh54ALZuhQULan9eeTl89BF06mS+HB58EObOhbw8x21wM6XlFczbcZwjOU7Wna0BEXfhwuXRR+Gbb+Dll/nvzQ9hCfCnU7Ow858zeTK8/bZx2dxyi8mD4iqSkyEhAfwazr/lmK5NWXcg63QqZYe46SZTeu/VV2tuqzXMng29e8Odd0JEBDRrBu++C1dcYWq0fvyx4za4kayCEn7/yToW7nbiy68WNJy7SBAc4YMP4JVX4M9/hocfZvuRXDo3D6tdqt+774Z//ctMsP7hD65zGzSQGPfKXNKtGRUa5wQsONh81nPnwp495297++0wYYL5NfX118aNNm8eZGfDb7+Z6JspU2DWrPP340FOV/1y04poEXfhwmPRIiMal14Kr7yC1pptabn0aBFR46mneegheOIJM+E6fXrdbdLajNwbiL/dRo8WETQNC2L+TidL5919t1ln8Prr1beZPdtEN/3lL2ZV67XXGrcOmC+IUaNMm3794IYbYPFi52xxMaeLsYu4C4IL2LcPrrkGOnaEr74Cf3+O5BaRXVhK95YOiDvA00+bL4j77oP16+tmV2am8Qs3sJG7n59idNdmLN59guIyJ3LFNGsGN99sXCrZdmqzFhSYX1/du8Pzz1dfvapxY/MLoF07GD8eNm503BYXk11g5myiQt2ThVTEXbhwKCw0oYxKGZ95hBHzbWnWlaktHMzn4udnRoxNm8J119kXn9rSwCJlKjOmW1MKSspZ7UyWSDATq4WF8P775x575hkTD//uuzWXJYyJgV9+MX/3sWPr9vdyAVnWkbu7EtWJuAsXDvfeCzt2wJdfniWi29NysfgpusY5kawrNtb4eA8dMpOtzvrfG1iMe2UGt48lJMDivGumd2/jWnnzTUhNPbN/2zYzb3LnnWfy0dRE69bw+eeQnu71GPocN9frFXEXLgw++sj8tH/ySRgz5qxD246cpEOTxgQHWJzre+BAM8E6e7YRIGewjdwboLgHB1gY2jGW+TuOO7daFczf7fhxkxLitttgyxbjj4+IgBdfdKyvwYNN3vh585yzxUVkFZbQ2I31ekXchYbPtm1m1D5qFDz11LmH03Lp3rKO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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "#对网络进行验证\n",
    "show_x = data_13_tr\n",
    "show_y = tr_mf_bm_l\n",
    "show_l = 81\n",
    "net.eval()\n",
    "net.to('cpu')\n",
    "predict = net(show_x)\n",
    "# predict = predict.data.numpy()\n",
    "\n",
    "MSE_show = criterion(predict, show_y)\n",
    "predict = predict.data.numpy()\n",
    "# 建立等差数列，（起始，终止，个数）\n",
    "x = np.linspace(1,show_l,show_l)\n",
    "column = 0\n",
    "plt.title('MF(RMSE:'+str('%.5g' % torch.sqrt(MSE_show))+')')\n",
    "plt.plot(x , show_y, label='origin')\n",
    "plt.plot(x, predict, color='red', label='predict')\n",
    "plt.legend()\n",
    "plt.show()\n"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "122afd33e14e141e8feafe6109b3cf33c81901f42114774f6f58cb0f50546406"
  },
  "kernelspec": {
   "display_name": "Python 3.8.11 ('ml2')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.11"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
